import * as fs from "fs";
import * as path from "path";
import * as morph from "ts-morph";
import { BuildMessage } from "./BuildMessage";
import { BuildTSBuffer } from "./BuildTSBuffer";

let fullNodeTypeList: string[] = [];
let fullNodeParentList: string[] = [];
let fullNodeCodeList: number[] = [];
let fullSchemaIdList: string[] = [];

async function BuildFlow(srcRootPath: string, srcFilePath: string, outFilePath: string) {
    const ext = path.extname(srcFilePath);
    if (ext != ".ts") {
        return;
    }
    const { tempFilePath, nodeTypeList, nodeParentList, nodeCodeList } = BuildMessage(srcFilePath, outFilePath);

    const filePathData = path.parse(srcFilePath);
    const bufferSchemaType = filePathData.name;
    const bufferFileName = bufferSchemaType + "_Proto" + ext;
    const realOutFilePath = path.join(outFilePath, bufferFileName);

    const schemaIdList: string[] = [];
    nodeTypeList.forEach(nodeType => {
        let schemaId = bufferSchemaType + "/" + nodeType;
        schemaIdList.push(schemaId);
    });

    fullNodeTypeList = fullNodeTypeList.concat(nodeTypeList);
    fullNodeParentList = fullNodeParentList.concat(nodeParentList);
    fullNodeCodeList = fullNodeCodeList.concat(nodeCodeList);
    fullSchemaIdList = fullSchemaIdList.concat(schemaIdList);

    // console.log(`=====>`);
    // console.log(srcRootPath);
    // console.log(outFilePath);
    // console.log(realOutFilePath);
    // console.log(bufferFileName);
    // console.log(`=====>`);

    if (fs.existsSync(realOutFilePath)) {
        fs.rmSync(realOutFilePath);
    }
    await BuildTSBuffer(tempFilePath, realOutFilePath);
}

async function TraverseDirectory(rootPath: string, dirPath: string, outPath: string) {
    const files = fs.readdirSync(dirPath);
    files.forEach(async (file) => {
        const filePath = path.join(dirPath, file);
        const stats = fs.statSync(filePath);
        if (stats.isDirectory()) {
            TraverseDirectory(rootPath, filePath, outPath);
        } else {
            BuildFlow(rootPath, filePath, outPath);
        }
    });
}

export function BuildProto(rootPath: string, filePath: string, outPath: string) {
    const stats = fs.statSync(filePath);
    if (stats.isDirectory()) {
        TraverseDirectory(rootPath, filePath, outPath);
    } else {
        BuildFlow(rootPath, filePath, outPath);
    }
}

function BuildTSBufferUtil(inputPath: string, nodeTypeList: string[], nodeParentList: string[], nodeCodeList: number[], schemaIdList: string[]) {
    const project = new morph.Project({ compilerOptions: { target: morph.ts.ScriptTarget.ES2016 } });
    project.addSourceFileAtPathIfExists(inputPath);
    // 获取包含当前光标位置的节点。
    const morphSourceFile = project.getSourceFileOrThrow(inputPath);
    const classDecl = morphSourceFile.getClass("TSBufferUtil");

    const type2SchemaIdMemberDecl = classDecl.getProperty("Type2SchemaIdDict");
    const type2SchemaIdMemberValueList: string[] = [];
    type2SchemaIdMemberValueList.push("{");

    const type2ParentMemberDecl = classDecl.getProperty("Type2ParentDict");
    const type2ParentMemberValueList: string[] = [];
    type2ParentMemberValueList.push("{");

    const type2ProtocolMemberDecl = classDecl.getProperty("Type2ProtocolDict");
    const type2ProtocolMemberValueList: string[] = [];
    type2ProtocolMemberValueList.push("{");

    const len = nodeTypeList.length;
    for (let i = 0; i < len; i++) {
        let nodeType = nodeTypeList[i];
        let nodeParent = nodeParentList[i];
        let nodeCode = nodeCodeList[i];
        let schemaId = schemaIdList[i];

        let type2SchemaIdMemberValue = `${nodeType}: "${schemaId}"`;
        let type2ParentMemberValue = `${nodeType}: "${nodeParent}"`;
        let type2ProtocolMemberValue = `${nodeType}: ${nodeCode}`;
        if (i != len - 1) {
            type2SchemaIdMemberValue += `,`;
            type2ParentMemberValue += `,`;
            type2ProtocolMemberValue += `,`;
        }
        type2SchemaIdMemberValueList.push(type2SchemaIdMemberValue);
        type2ParentMemberValueList.push(type2ParentMemberValue);
        type2ProtocolMemberValueList.push(type2ProtocolMemberValue);
    }
    type2SchemaIdMemberValueList.push("}");
    type2SchemaIdMemberDecl.setInitializer(type2SchemaIdMemberValueList.join("\n"));

    type2ParentMemberValueList.push("}");
    type2ParentMemberDecl.setInitializer(type2ParentMemberValueList.join("\n"));

    type2ProtocolMemberValueList.push("}");
    type2ProtocolMemberDecl.setInitializer(type2ProtocolMemberValueList.join("\n"));

    morphSourceFile.formatText();

    const newFileContent = morphSourceFile.getFullText();
    fs.writeFileSync(inputPath, newFileContent);
}

const srcFolder = "Codes/Scripts";
const protoFolder = "Proto";
const targetFolder = "Codes/scripts/Codes/Model/Generate/Share/Message";
const rootPath = path.join(__dirname, "../../../");
const tempPath = path.join(rootPath, targetFolder);
const realPath = path.join(rootPath, protoFolder);
BuildProto(realPath, realPath, tempPath);

const utilFilePath = "Support/Share/TSBuffer/TSBufferUtil.ts";
const utilFileFolder = path.join(rootPath, srcFolder);
const utilFileFullPath = path.join(utilFileFolder, utilFilePath);
BuildTSBufferUtil(utilFileFullPath, fullNodeTypeList, fullNodeParentList, fullNodeCodeList, fullSchemaIdList);